package com.slowfly.rule.engine.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.slowfly.rule.engine.bean.CacheBean;
import com.slowfly.rule.engine.component.RedisComponent;
import com.slowfly.rule.engine.constants.IRiskConstants;
import com.slowfly.rule.engine.entity.Feature;
import com.slowfly.rule.engine.enums.FeatureStatusEnum;
import com.slowfly.rule.engine.enums.OptEnum;
import com.slowfly.rule.engine.features.BaseFeatureClass;
import com.slowfly.rule.engine.mapper.FeatureMapper;
import com.slowfly.rule.engine.model.FeatureValue;
import com.slowfly.rule.engine.param.FeatureParam;
import com.slowfly.rule.engine.param.ListFeaturesParam;
import com.slowfly.rule.engine.result.FeatureResult;
import com.slowfly.rule.engine.result.PageResult;
import com.slowfly.rule.engine.service.IFeatureService;
import com.slowfly.rule.engine.util.JsonUtils;
import com.slowfly.rule.engine.util.PageResultConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author shalongfei
 * @since 2024-02-22
 */
@Slf4j
@Service
public class FeatureServiceImpl extends ServiceImpl<FeatureMapper, Feature> implements IFeatureService {

    private Map<Integer, Feature> featureCache;
    @Autowired
    private RedisComponent redisComponent;
    @Autowired
    private Map<String, BaseFeatureClass> featureClassMap;

    public void setCache() {
        Map<Integer, Feature> featureCache = Maps.newConcurrentMap();
        for (Feature scene : list()) {
            featureCache.put(scene.getId(), scene);
        }
        this.featureCache = featureCache;
    }

    public void editCache(int type, int id) {
        if (type == OptEnum.ADD.getCode() || type == OptEnum.EDIT.getCode()) {
            featureCache.put(id, getById(id));
        } else if (type == OptEnum.DELETE.getCode()) {
            featureCache.remove(id);
        }
    }

    public Feature get(Integer featureId) {
        return featureCache.get(featureId);
    }

    public List<FeatureResult> listFeature() {
        LambdaQueryWrapper<Feature> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Feature::getStatus, FeatureStatusEnum.NORMAL.getValue());
        return BeanUtil.copyToList(list(queryWrapper), FeatureResult.class);
    }

    public PageResult<FeatureResult> pageFeature(FeatureParam param) {
        LambdaQueryWrapper<Feature> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Feature::getStatus, FeatureStatusEnum.NORMAL.getValue());
        queryWrapper.like(StringUtils.isNotBlank(param.getName()), Feature::getName, param.getName());
        queryWrapper.eq(StringUtils.isNotBlank(param.getClassCode()), Feature::getClassCode, param.getClassCode());
        queryWrapper.orderByDesc(Feature::getUpdateTime);
        Page<Feature> page = page(new Page<>(param.getPageNo(), param.getPageSize()), queryWrapper);
        return PageResultConvert.convert(page, FeatureResult.class);
    }

    public boolean addFeature(FeatureParam param) {
        Feature feature = new Feature();
        BeanUtils.copyProperties(param, feature);
        feature.setStatus(FeatureStatusEnum.NORMAL.getValue());
        boolean saved = save(feature);
        redisComponent.publish(IRiskConstants.FEATURE_CHANEL, new CacheBean(OptEnum.ADD.getCode(), feature.getId()));
        return saved;
    }

    public boolean editFeature(FeatureParam param) {
        Feature feature = new Feature();
        BeanUtils.copyProperties(param, feature);
        boolean updated = updateById(feature);
        redisComponent.publish(IRiskConstants.FEATURE_CHANEL, new CacheBean(OptEnum.EDIT.getCode(), param.getId()));
        return updated;
    }

    public boolean deleteFeature(FeatureParam param) {
        Feature feature = new Feature();
        BeanUtils.copyProperties(param, feature);
        feature.setStatus(FeatureStatusEnum.DELETE.getValue());
        boolean updated = updateById(feature);
        redisComponent.publish(IRiskConstants.FEATURE_CHANEL, new CacheBean(OptEnum.DELETE.getCode(), param.getId()));
        return updated;
    }

    public List<FeatureValue> listFeatureValues(long riskId, Object riskParam, Set<Integer> featureIds) {
        ListFeaturesParam param = new ListFeaturesParam();
        param.setRiskParam(riskParam);
        param.setFeatureIds(featureIds);
        log.info("listFeatureValues {} {}", riskId, JsonUtils.toJson(param));
        List<FeatureValue> featureValues = listFeatureValues(param);
        log.info("listFeatureValues {} {}", riskId, JsonUtils.toJson(featureValues));
        return featureValues;
    }

    private List<FeatureValue> listFeatureValues(ListFeaturesParam param) {
        List<FeatureValue> featureValues = Lists.newArrayList();
        for (Integer featureId : param.getFeatureIds()) {
            Feature feature = get(featureId);
            BaseFeatureClass featureClass = featureClassMap.get(feature.getClassCode());
            Object featureValue = featureClass.getFeatureValue(param, feature);
            featureValues.add(new FeatureValue(featureId, featureValue));
        }
        return featureValues;
    }
}
